#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <signal.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <stddef.h>
#include <linux/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/spi/spidev.h>

#define dev_name "/dev/spidev0.0"

typedef enum {
    SPI_IOC_RD_MODE_E,
    SPI_IOC_WR_MODE_E,

    SPI_IOC_RD_LSB_FIRST_E,
    SPI_IOC_WR_LSB_FIRST_E,

    SPI_IOC_RD_BITS_PER_WORD_E,
    SPI_IOC_WR_BITS_PER_WORD_E,

    SPI_IOC_RD_MAX_SPEED_HZ_E,
    SPI_IOC_WR_MAX_SPEED_HZ_E,
} MCU_SPI_IOCTL_E;

static int spidev_read(int fd, char *buf, int len)
{
    // 读半双工方式
    int ret = 0;
    ret = read(fd, buf, len);
    if (ret < 0) {
        perror("spidev read failed\n");
        return -1;
    }

    return 0;
}

static int spidev_write(int fd, char *buf, int len)
{
    // 写是半双工方式
    int ret = 0;
    ret = write(fd, buf, len);
    if (ret < 0) {
        perror("spidev read failed\n");
        return -1;
    }
    
    return 0;
}

static int read_after_write(int fd, char *buf, char *rx_buf, int tx_len) 
{
    // 先写再读
    struct spi_ioc_transfer xfer[2];
    int ret = 0;

    memset(rx_buf, 0, ARRAY_SIZE(rx_buf));

    // 发送
    xfer[0].tx_buf = (unsigned long)buf;
    xfer[0].len = tx_len;

    // 接受
    xfer[1].rx_buf = (unsigned long)rx_buf;
    xfer[1].len = ARRAY_SIZE(rx_buf);

    ret = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
    if (ret < 0) {
        perror("spidev SPI_IOC_MESSAGE failed\n");
        return -1;
    }

    return 0;
}

static int read_write_timing(int fd, char *tx_buf, char *rx_buf, int len)
{
    // 同时写和同时读
    struct spi_ioc_transfer xfer[1];
    int ret = 0;

    memset(rx_buf, 0, ARRAY_SIZE(rx_buf));

    // 同时发送和接受
    xfer[0].tx_buf = (unsigned long)tx_buf;
    xfer[0].rx_buf = (unsigned long)rx_buf;
    xfer[0].len = len;

    ret = ioctl(fd, SPI_IOC_MESSAGE(1), xfer);
    if (ret < 0) {
        perror("spidev SPI_IOC_MESSAGE failed\n");
        return -1;
    }

    return 0;
}

static int spidev_ioctl(int fd, unsigned int cmd, unsigned long val) {
    int ret = 0;
    switch (cmd) {
        case SPI_IOC_RD_MODE_E:
            cmd = SPI_IOC_RD_MODE;
            break;
        case SPI_IOC_WR_MODE_E:
            cmd = SPI_IOC_WR_MODE;
            break;
        case SPI_IOC_RD_LSB_FIRST_E:
            cmd = SPI_IOC_RD_LSB_FIRST;
            break;
        case SPI_IOC_WR_LSB_FIRST_E:
            cmd = SPI_IOC_WR_LSB_FIRST;
            break;
        case SPI_IOC_RD_BITS_PER_WORD_E:
            cmd = SPI_IOC_RD_BITS_PER_WORD;
            break;
        case SPI_IOC_WR_BITS_PER_WORD_E:
            cmd = SPI_IOC_WR_BITS_PER_WORD;
            break;
        case SPI_IOC_RD_MAX_SPEED_HZ_E:
            cmd = SPI_IOC_RD_MAX_SPEED_HZ;
            break;
        case SPI_IOC_WR_MAX_SPEED_HZ_E:
            cmd = SPI_IOC_WR_MAX_SPEED_HZ;
            break;
    }

    ret = ioctl(fd, cmd, &val);
    if (ret < 0) {
        perror("spidev ioctl failed\n");
        return -1;
    }

    return 0;
}

int main(int argc, char const *argv[])
{
    int fd = 0;
    char w_buf[32];
    char r_buf[32];
    int ret = 0;

    memset(w_buf, 0, sizeof(w_buf));
    memset(r_buf, 0, sizeof(r_buf));

    fd = open(dev_name, O_RDWR);
    if (fd < 0) {
        perror("spidev open failed\n");
        exit(1);
    }

    return 0;
}

